#include "PWMDriver.h"
#include "DSP2833x_Device.h"
#include "DSP2833x_EPwm_defines.h"

// SYSCLKOUT (System Clock) = 150Mhz
// TBCLK = 2343750Hz (divide by 64)
// PWMClock = 50Hz (TBCLK/(46875+1)) [20ms]

bool PWMDriver::Init() 
{
	EALLOW;
	// configure GPIO pins
	GpioCtrlRegs.GPAPUD.bit.GPIO0 = 0;    // Enable pull-up on GPIO0 (EPWM1A)
    GpioCtrlRegs.GPAPUD.bit.GPIO1 = 0;    // Enable pull-up on GPIO1 (EPWM1B)   
    GpioCtrlRegs.GPAPUD.bit.GPIO2 = 0;    // Enable pull-up on GPIO2 (EPWM2A)
    GpioCtrlRegs.GPAPUD.bit.GPIO3 = 0;    // Enable pull-up on GPIO3 (EPWM2B)  
    GpioCtrlRegs.GPAMUX1.bit.GPIO0 = 1;   // Configure GPIO0 as EPWM1A
    GpioCtrlRegs.GPAMUX1.bit.GPIO1 = 1;   // Configure GPIO1 as EPWM1B
    GpioCtrlRegs.GPAMUX1.bit.GPIO2 = 1;   // Configure GPIO0 as EPWM2A
    GpioCtrlRegs.GPAMUX1.bit.GPIO3 = 1;   // Configure GPIO1 as EPWM2B
    EDIS;
    
    // Setup TBCLK
	EPwm1Regs.TBPRD = 46874; // Period = 46875 TBCLK counts
	EPwm1Regs.CMPA.half.CMPA = 46874/20; // Compare A = 5% duty 
	EPwm1Regs.CMPB = 46874/20; // Compare B = 5% duty
	EPwm1Regs.TBPHS.half.TBPHS = 0; // Set Phase register to zero
	EPwm1Regs.TBCTR = 0; // clear TB counter
	EPwm1Regs.TBCTL.bit.CTRMODE = TB_COUNT_UP;
	EPwm1Regs.TBCTL.bit.PHSEN = TB_DISABLE; // Phase loading disabled
	EPwm1Regs.TBCTL.bit.PRDLD = TB_SHADOW;
	EPwm1Regs.TBCTL.bit.SYNCOSEL = TB_SYNC_DISABLE;
	EPwm1Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1; // TBCLK = SYSCLK
	EPwm1Regs.TBCTL.bit.CLKDIV = 0x06; // divide by 64
	EPwm1Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW;
	EPwm1Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW;
	EPwm1Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO; // load on CTR = Zero
	EPwm1Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO; // load on CTR = Zero
	EPwm1Regs.AQCTLA.bit.ZRO = AQ_SET;
	EPwm1Regs.AQCTLA.bit.CAU = AQ_CLEAR;
	EPwm1Regs.AQCTLB.bit.ZRO = AQ_SET;
	EPwm1Regs.AQCTLB.bit.CBU = AQ_CLEAR;
	
	// Setup TBCLK
	EPwm2Regs.TBPRD = 46874; // Period = 46875 TBCLK counts
	EPwm2Regs.CMPA.half.CMPA = 46874/20; // Compare A = 5% duty 
	EPwm2Regs.CMPB = 46874/20; // Compare B = 5% duty
	EPwm2Regs.TBPHS.half.TBPHS = 0; // Set Phase register to zero
	EPwm2Regs.TBCTR = 0; // clear TB counter
	EPwm2Regs.TBCTL.bit.CTRMODE = TB_COUNT_UP;
	EPwm2Regs.TBCTL.bit.PHSEN = TB_DISABLE; // Phase loading disabled
	EPwm2Regs.TBCTL.bit.PRDLD = TB_SHADOW;
	EPwm2Regs.TBCTL.bit.SYNCOSEL = TB_SYNC_DISABLE;
	EPwm2Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1; // TBCLK = SYSCLK
	EPwm2Regs.TBCTL.bit.CLKDIV = 0x06; // divide by 64
	EPwm2Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW;
	EPwm2Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW;
	EPwm2Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO; // load on CTR = Zero
	EPwm2Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO; // load on CTR = Zero
	EPwm2Regs.AQCTLA.bit.ZRO = AQ_SET;
	EPwm2Regs.AQCTLA.bit.CAU = AQ_CLEAR;
	EPwm2Regs.AQCTLB.bit.ZRO = AQ_SET;
	EPwm2Regs.AQCTLB.bit.CBU = AQ_CLEAR;
	
	SetPWMuSec(0, 1000);
	SetPWMuSec(1, 1000);
	SetPWMuSec(2, 1000);
	SetPWMuSec(3, 1000);
	
    return true;
}

void PWMDriver::SetPWM(int index, float dutyCycle)
{
	Uint16 duty = (Uint16)((dutyCycle/100)*46875.0f);
	if( index == 0 )
	{
		// PWM1A
		EPwm1Regs.CMPA.half.CMPA = duty; // adjust duty for output EPWM1A
		
	}
	else if( index == 1 )
	{
		// PWM1B
		EPwm1Regs.CMPB = duty; // adjust duty for output EPWM1B
	}
	else if( index == 2 )
	{
		// PWM2A
		EPwm2Regs.CMPA.half.CMPA = duty; // adjust duty for output EPWM2A
	}
	else if( index == 3 )
	{
		// PWM2B
		EPwm2Regs.CMPB = duty; // adjust duty for output EPWM2B
	}
}

void PWMDriver::SetPWMuSec(int index, int uSec)
{
	float duty = (uSec/20000.0f)*100;
	
	SetPWM(index, duty);
}

